package pl.edu.agh.thieves.cuckoo;

import pl.edu.agh.thieves.common.Item;
import pl.edu.agh.thieves.common.Iteration;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;

public class CuckooSearch {
	private final Cuckoo cuckoo;
	private final ArrayList<Item> allItems;
	// private final double capacity;
	private final int numberOfNests;
	private final int probability;
	private final int iterations;
	private final Random random;

	public CuckooSearch(Collection<Item> items, double capacity, int n,
			int probability, int iter) {
		allItems = new ArrayList<Item>();
		allItems.addAll(items);
		// this.capacity=capacity;
		numberOfNests = n;
		this.probability = probability;
		cuckoo = new Cuckoo(capacity, allItems);
		iterations = iter;
		random = new Random();
	}

	public OptimalSolutionCuckoo search() {
		long startTime;
		long resultTime;
		long timeOfAll;
		ArrayList<Iteration> iterationsArray = new ArrayList<Iteration>();
		// double [] graphData=new double[iterations];

		startTime = System.nanoTime();
		ArrayList<Egg> nests = new ArrayList<Egg>();
		nests.addAll(getInitialNests());
		Egg bestEgg = findBestEgg(nests);
		Egg newEgg = null;
		resultTime = System.nanoTime() - startTime;
		int index = 0;
		int bestEggIter = 0;

		for (int i = 0; i < iterations; i++) {
			newEgg = cuckoo.generateNewEgg();
			index = random.nextInt(numberOfNests);
			nests.add(index, newEgg.getBetterEgg(nests.get(index)));

			nests = detectFalseEggs(nests);
			if (!bestEgg.isBetter(findBestEgg(nests))) {
				resultTime = System.nanoTime() - startTime;
				bestEggIter = i;
			}
			bestEgg = bestEgg.getBetterEgg(findBestEgg(nests));
			//System.out.println(bestEgg.getEggValue()+"");
			iterationsArray.add(new Iteration(i, bestEgg.getEggValue()));
			// graphData[i]=bestEgg.getEggValue();

		}
		timeOfAll = System.nanoTime() - startTime;
		return new OptimalSolutionCuckoo(bestEgg.getItems(), bestEggIter,
				resultTime, timeOfAll, iterationsArray);

	}

	public Collection<Egg> getInitialNests() {
		ArrayList<Egg> nests = new ArrayList<Egg>();

		for (int i = 0; i < numberOfNests; i++)
			nests.add(cuckoo.generateNewEgg());

		return nests;
	}

	public Egg findBestEgg(Collection<Egg> eggs) {
		Egg bestEgg = null;

		for (Egg egg : eggs) {
			if (bestEgg == null)
				bestEgg = egg;
			else {
				bestEgg = bestEgg.getBetterEgg(egg);
			}
		}

		return bestEgg;
	}

	public ArrayList<Egg> detectFalseEggs(ArrayList<Egg> nests) {
		int chance;

		for (int i = 0; i < numberOfNests; i++) {
			chance = random.nextInt(101);
			if (chance < probability)
				nests.add(i, cuckoo.generateNewEgg());
		}

		return nests;
	}
}
